﻿namespace DynaBoard
{
    using System;
    using System.Text.RegularExpressions;
    using System.Collections.Generic;
    using System.Text;

    [IsRequired(true)]
    [RegexPattern("[^\x00-\x1f]")]
    public class PostBody : UserInputString 
    {
        private const string whitelist = 
            "b|i|u|s|strike|sup|sub|strong|tt|em";
   
        public PostBody(string body)
            : base(body, true)
        {
            this.value = Regex.Replace(body, @"<(.|\n)*?>", match =>
            {
                return !Regex.IsMatch(match.Value, "</?(" + PostBody.whitelist + ")>", RegexOptions.IgnoreCase) ?
                    string.Empty :
                    match.Value;
            })
            .Replace("\n", "<br>")
            .Replace(" ", "&nbsp;");

            this.CloseOpenTags();
        }

        public void CloseOpenTags()
        {
            var openTags = new Dictionary<string, int>();

            foreach (Match match in Regex.Matches(this.value, "<.*?>"))
            {
                string matchValue = match.Value.Substring(1, match.Value.Length - 2).ToLower();
                bool closingTag = matchValue[0] == '/';
                string tag = closingTag ? matchValue.Substring(1) : matchValue;

                if (!openTags.ContainsKey(tag))
                {
                    openTags.Add(tag, closingTag ? -1 : 1);
                    continue;
                }

                openTags[tag] += closingTag ? -1 : 1;
            }

            string html = this.value;

            var buffer = new StringBuilder(html.Length);
            buffer.Append(html);

            foreach (KeyValuePair<string, int> tag in openTags)
            {
                for (int i = tag.Value; i > 0; i--)
                {
                    buffer.Append("</" + tag.Key + ">");
                }
            }

            this.value = buffer.ToString();
        }

        public static implicit operator String(PostBody body)
        {
            return body.value;
        }

        public static implicit operator PostBody(string body)
        {
            return new PostBody(body);
        }
    }
}